
"""

<html>
<head>
<meta charset="utf-8">	
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- head -->
<script type="text/javascript"  src="/static_base/vue2.6.14.js"></script>
<script src="/static_base/element_ui_2.0.3_index.js"></script>
<link href="/static_base/element_ui.css" rel="stylesheet">
<script type="text/javascript"  src="/static_base/base.js"></script>
<link rel="stylesheet" href="/static_base/iconfont.css">

"""
默认head=r"""
<meta charset="utf-8">	
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- head -->
<script type="text/javascript"  src="/static_base/vue2.6.14.js"></script>
<script type="text/javascript"  src="/static_base/base.js"></script>
<script type="text/javascript"  src="/static_base/js-md5.js"></script>


<link rel="stylesheet" href="/static_base/iconfont.css">
<link rel="stylesheet" href="/static_base/base.css">
<script type="text/javascript"  src="/static_base/default.js"></script>
<link rel="stylesheet" href="/static_base/default.css">
<link href="\static_base\vuetify2.6.4.min.css" rel="stylesheet">
<script type="text/javascript"  src="\static_base\vuetify2.6.4.js"></script>
"""
import os,sys,yaml,json
def read_yaml(path):
    #读取用户目录下的yaml配置文件
    with open(path, 'r',encoding='utf-8') as file:  
       return yaml.safe_load(file)
def save_yaml(path,data):
    with open(path, 'w',encoding='utf-8') as file:  
        yaml.dump(data, file, default_flow_style=False, allow_unicode=True)  
pro=os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
静态文件夹所在目录=os.path.join(pro,"easy_edit","_static_dir")
# class body:

# print(pro)
class create_head:
    def __init__(self,obj):
        self.obj=obj
        self.head=self.default_head
    default_head=r"""
<meta charset="utf-8">	
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- head -->
<script type="text/javascript"  src="/static_base/vue2.6.14.js"></script>
<script type="text/javascript"  src="/static_base/base.js"></script>
<script type="text/javascript"  src="/static_base/js-md5.js"></script>


<link rel="stylesheet" href="/static_base/iconfont.css">
<link rel="stylesheet" href="/static_base/base.css">
<script type="text/javascript"  src="/static_base/default.js"></script>
<link rel="stylesheet" href="/static_base/default.css">
"""
    def 返回标签(self,static_path):
        # print("static_path,static_path",static_path)
        if static_path.split(".")[-1]=="js":
            return f'<script type="text/javascript"  src="{static_path}"></script>\n'
        elif static_path.split(".")[-1]=='css':
            return f'<link href="{static_path}" rel="stylesheet">\n'
    def 从静态文件夹搜索匹配的文件然后返回完整路径(self,static_name):
        # TODO:从当前项目加载静态文件
        # 从静态目录下获取静态文件
        if os.path.isfile(静态文件夹所在目录+os.sep+static_name):
            return "\\static_base\\"+static_name
    def 解析数据_获取组件需要额外加载的js和css(self):
        names=set()
        组件字典=self.obj.page_config['page_dict']
        for 组件id in 组件字典:
            use_vue=组件字典[组件id]['base_info'].get("use_vue")
            use_vue_info=组件字典[组件id]['base_info'].get("use_vue_info")
            if use_vue is not None:
# use_vue_info: {"vuetify":{"head":["vuetify2.6.4.min.css","vuetify2.6.4.js"],"js":"window.vuetify=new Vuetify();"}}
                for item in use_vue:
                    for static_name in use_vue_info[item]['head']:
                        if static_name in names:continue
                        names.add(static_name)
                        # print(static_name)
                        self.head+=self.返回标签(self.从静态文件夹搜索匹配的文件然后返回完整路径(static_name))
                         
    def run(self):
        self.解析数据_获取组件需要额外加载的js和css()
        return self.head
class create_body:
    def __init__(self,obj):
        self.obj=obj
        self.run_flag=0
        self.js_dct={}#存放属性容器-2类型的数据
    def 获取组件深度_用于优先生成最底层的组件的代码(self):
        组件字典=self.obj.page_config['page_dict']
        #获取组件的路径 深度
        临时存储=set() #保存已经处理过的  id
        路径深度dct={}  #保存处理后的路径   {1:[],2:[],4:[['1.2.3.4','2.3.3.5']]}    key代表路径深度    里面的元素是指同一父容器下的排序

        #先获取到所有id  的路径
        路径字典={}#{id:''}
        for 组件id in 组件字典:
            路径=组件id
            当前数据=组件字典[组件id]
            父节点id=当前数据['base_info']['father_id']
            #不是根节点就持续查找上一级节点 然后拼接路径
            while 父节点id!="-1":
                路径=父节点id+'.'+路径
                当前数据=组件字典[父节点id]
                父节点id=当前数据['base_info']['father_id']
            路径字典[组件id]=路径
        #遍历id 将拥有相同父容器的 归类
        for 组件id in 路径字典:
            if 组件id in 临时存储:continue#已经处理过不需要再处理
            路径长度=len(路径字典[组件id].split("."))
            if 路径长度==1:
                父容器的con_dct=self.obj.page_config['base_info']['con_dct']
            else:
                父组件id=路径字典[组件id].split(".")[-2]
                父容器的con_dct= 组件字典[父组件id]["base_info"]['con_dct']
            if 路径深度dct.get(路径长度) is None:路径深度dct[路径长度]=[]
            当前组件所在ref=组件字典[组件id]["base_info"]['ref']
            append_lst=[]
            for 排序后的组件id in 父容器的con_dct[当前组件所在ref]:
                append_lst.append(路径字典[排序后的组件id])
                临时存储.add(排序后的组件id)
            路径深度dct[路径长度].append(append_lst)
        res=[]
        for k in sorted(路径深度dct.keys(),reverse=True):
            res.append(路径深度dct[k])
        #res=[[['1.12.13.22.31', '1.12.13.22.40', '1.12.13.22.42'], ['1.12.14.23.32', '1.12.14.23.41', '1.12.14.23.44'], ['1.12.15.26.33', '1.12.15.26.47'], ['1.12.17.24.34', '1.12.17.24.43'], ['1.12.18.25.35', '1.12.18.25.45'], ['1.12.19.27.36', '1.12.19.27.50'], ['1.12.16.30.37', '1.12.16.30.48', '1.12.16.30.49'], ['1.12.21.29.38', '1.12.21.29.46'], ['1.12.20.28.39', '1.12.20.28.51']], [['1.12.13.22'], 
        #['1.12.14.23'], ['1.12.17.24'], ['1.12.18.25'], ['1.12.15.26'], ['1.12.19.27'], ['1.12.20.28'], ['1.12.21.29'], ['1.12.16.30']], [['1.12.13', '1.12.14', '1.12.15', '1.12.16', '1.12.17', '1.12.18', '1.12.19', '1.12.20', '1.12.21']], [['1.12']], [['1']]]
        
        
        # print("1.生成body深度路径",res)
        return res
    def 生成body内容(self):
        lst=self.获取组件深度_用于优先生成最底层的组件的代码()
        dct={}  
        for item in lst:
            while len(item):
                new_con_lst=item.pop()
                for 路径 in new_con_lst:
                    self.生成单个组件的内容(dct,路径.split(".")[-1])
        完整bodyhtml=self.生成单个组件的内容(dct,"-1")
        # print("完整body html:")
        return 完整bodyhtml
    def run(self):
        if self.run_flag==0:
            self.run_data={"html":self.生成body内容(),"js":self.js_dct}
            self.run_flag=1
        return self.run_data
    def 生成单个组件的内容(self,dct,组件id):
        组件字典=self.obj.page_config['page_dict']
        # print("当前处理id",组件id)
        only_id="id_"+self.obj.项目id+'_'+self.obj.page_id+"_"+组件id
        if 组件id=="-1":
            only_id="id_"+self.obj.项目id+'_'+self.obj.page_id+"_0"
            组件数据=self.obj.page_config['base_info']
            组件使用模板="a_1_1_1_2_1_div"
            now_html=f'<{组件使用模板} id="{only_id}"'
            # {__style:{__edit_flag__:false},height:"auto",width:"auto",min_width:"100%",min_height:"100%",flex_grow:"1"}
        else:
            组件数据=组件字典[组件id]['base_info']
            组件使用模板=组件数据['temp_id']+'_'+str(组件数据['version'])
            #deepcopy_data 保存组件数据
            #all_set_data 保存所有组件的数据
            #con2_father_this 保存con2类型容器 父组件 的this
            #con2idx 保存当前组件处于父组件所在的索引 
            now_html=f'<{组件使用模板} id="{only_id}" :deepcopy_data="all_set_data.{only_id}" :all_set_data="all_set_data" :con2_father_this="con2_father_this" :con2_idx="con2_idx"'
        #判断组件类型是否是容器
        if 组件数据.get('con'):
            #判断组件类型是否是属性容器 ：将指定子\孙子组件的属性放置于此容器进行同步
            if 组件数据.get('con')=='2':
                self.js_dct[only_id]={"slot_data":{}}
                for slot_name in 组件数据['con_dct']:
                    self.js_dct[only_id]['slot_data'][slot_name]=""
                    for child_id in 组件数据['con_dct'][slot_name]:
                        self.js_dct[only_id]['slot_data'][slot_name]+=("\n"+dct[child_id])
                now_html+=">\n"
            else:
                #普通容器 遍历保存
                now_html+=">\n"
                for slot_name in 组件数据['con_dct']:
                    # <template v-slot:header>
                    #     <div class="header">这是头部内容</div>
                    # </template>
                    slot_html=f"    <template v-slot:{slot_name}>\n"
                    slot_item=组件数据['con_dct'][slot_name]
                    for 子组件id in slot_item:
                        slot_html+="\n".join(["        "+item for item in dct[子组件id].split("\n")])
                        slot_html+="\n"
                    slot_html=slot_html+"    </template>"
                    now_html=now_html+slot_html+"\n"
        #普通组件
        else:
            now_html+=">\n"

        now_html=now_html+f"</{组件使用模板}>"
        # print(f"组件 {组件id} 的hmtl:")
        # print(now_html)
        dct[组件id]=now_html
        return now_html
    
class create_js:
    def __init__(self,obj):
        self.obj=obj
    def 获取要额外加载的js和css以及相应的初始化(self):
        all_add={}
        组件字典=self.obj.page_config['page_dict']
        for 组件数据 in 组件字典.values():
            use_vue=组件数据['base_info'].get("use_vue")
            use_vue_info=组件数据['base_info'].get("use_vue_info")
            if use_vue is not None:
# use_vue_info: {"vuetify":{"head":["vuetify2.6.4.min.css","vuetify2.6.4.js"],"js":"window.vuetify=new Vuetify();"}}
                for item in use_vue:
                    if item not in all_add:
                            all_add[item]=use_vue_info[item]['js']
        # res=all_add.values()
        return all_add
    def 生成js数据字典(self,js_dct):
        all_set_data={
            ("id_"+self.obj.项目id+'_'+self.obj.page_id+'_0'):{"__only_id":"id_"+self.obj.项目id+'_'+self.obj.page_id+'_0',"height":"auto","width":"auto","min_width":"100%","min_height":"100%","flex_grow":"1","__style":{"__edit_flag__":False}},

            }
        组件字典=self.obj.page_config['page_dict']
        for 组件id in 组件字典:
            only_id="id_"+self.obj.项目id+'_'+self.obj.page_id+'_'+组件id
            组件数据=组件字典[组件id]
            data=组件数据['base_info'].get('data',{})
            # print("判断组件的con是否为2",only_id,组件数据['base_info'].get("con"))
            if 组件数据['base_info'].get("con")=="2":
                data['slot_data']=js_dct[only_id]['slot_data']
                all_set_data[only_id]=data
            else:
                # print("普通组件",data)
                all_set_data[only_id]=data
            all_set_data[only_id]['__only_id']=only_id
        # print("alljs",all_set_data['id_1_3_107_3_1'].get("slot_data"))
        # input("..")
        return json.dumps(all_set_data)
    def run(self,js_dct):
        all_add=self.获取要额外加载的js和css以及相应的初始化()
        res="\nwindow.component2_edit_flag=false;\n"
        for item in all_add.values():
            res+=(item+';\n')
        res+=r"new Vue({el:'#id_"+f"{self.obj.项目id}_{self.obj.page_id}_0',\n"
        all_set_data=self.生成js数据字典(js_dct)
        #vuetify
        #vue的data数据
        res+=f'data:{{ all_set_data:{all_set_data},"con2_father_this":null,"con2_idx":"null", }},\n'
        #加载上类似vuetify的库
        for item in all_add.keys():
            res+=(item+',\n')
        #mounted数据
        res+="mounted:function(){\n"
        #######################################此处为mounted数据
        res+="this.$nextTick(() => {\n"
        #######################################此处为nexttick数据
        res+="\n});}});"
        return res
class tohtml:
    def __init__(self,**kwargs):
        self.page_config=kwargs.get("page_config")#页面数据
        self.all_config=kwargs.get("all_config")
        self.page_id=kwargs.get("page_id")#页面id
        self.项目id=self.all_config.get("project_id")
    def 加载默认head(self,):
        return 默认head
    #非递归实现
    #获取所有组件的 路径,根据路径的深度 来依次生成代码,按照路径最深的代码 先生成的逻辑 逐步生成最后的根节点
    #TODO: 此函数可以优化计算方式 提升计算效率 
    def tohtml(self):
        h_obj=create_head(self)
        b_obj=create_body(self)
        # print("js",b_obj.run()['js'])
        # input("")
        j_obj=create_js(self)

        #加载head
        res="""<html><head>"""
        res+=h_obj.run()
        res+="</head>\n"
        #加载body
        res+="<body>\n"
        res+=b_obj.run()['html']
        res+="\n<script>\n(async () => {  "
        #加载vue相关配置
        # res+="window.vuetify=new Vuetify();\n"
        #加载vue
        # res+=self.生成js()
        res+=j_obj.run(js_dct=b_obj.run()['js'])
        res+="})();</script>\n"
        #最后
        res+="</body></html>"
        #返回数据
        return res

if __name__=="__main__":
    config=read_yaml(os.path.dirname(os.path.abspath(__file__))+os.sep+"解析yaml配置文件中的页面数据_将之转为html.yaml")
    页面id='3'
    page_config=config['page_config']['dict']['1']['dict'][页面id]['dict']['1']
    t=tohtml(page_config=page_config,all_config=config,page_id=页面id)
    with open(os.path.dirname(os.path.abspath(__file__))+os.sep+"解析yaml配置文件中的页面数据_将之转为html.html","w",encoding='utf-8')as f:
        f.write(t.tohtml())
    # print()